/*!
 * @file        apm32f4xx_usart.c
 *
 * @brief       This file provides all the USART firmware functions
 *
 * @version     V1.0.2
 *
 * @date        2022-06-23
 *
 * @attention
 *
 *  Copyright (C) 2021-2022 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be usefull and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
 *  and limitations under the License.
 */

#include "apm32f4xx_usart.h"
#include "apm32f4xx_rcm.h"

/** @addtogroup APM32F4xx_StdPeriphDriver
  @{
*/

/** @defgroup USART_Driver
  * @brief USART driver modules
  @{
*/

/** @defgroup USART_Functions
  @{
*/

/*!
 * @brief     Reset usart peripheral registers to their default reset values
 *
 * @param     USARTx: where x can be 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or
 *                    UART peripheral.
 *
 * @retval    None
 */
void USART_Reset(USART_T* usart)
{
    if (USART1 == usart)
    {
        RCM_EnableAPB2PeriphReset(RCM_APB2_PERIPH_USART1);
        RCM_DisableAPB2PeriphReset(RCM_APB2_PERIPH_USART1);
    }
    else if (USART2 == usart)
    {
        RCM_EnableAPB1PeriphReset(RCM_APB1_PERIPH_USART2);
        RCM_DisableAPB1PeriphReset(RCM_APB1_PERIPH_USART2);
    }
    else if (USART3 == usart)
    {
        RCM_EnableAPB1PeriphReset(RCM_APB1_PERIPH_USART3);
        RCM_DisableAPB1PeriphReset(RCM_APB1_PERIPH_USART3);
    }
    else if (UART4 == usart)
    {
        RCM_EnableAPB1PeriphReset(RCM_APB1_PERIPH_UART4);
        RCM_DisableAPB1PeriphReset(RCM_APB1_PERIPH_UART4);
    }
    else if (UART5 == usart)
    {
        RCM_EnableAPB1PeriphReset(RCM_APB1_PERIPH_UART5);
        RCM_DisableAPB1PeriphReset(RCM_APB1_PERIPH_UART5);
    }
    else if (USART6 == usart)
    {
        RCM_EnableAPB2PeriphReset(RCM_APB2_PERIPH_USART6);
        RCM_DisableAPB2PeriphReset(RCM_APB2_PERIPH_USART6);
    }
    else if (UART7 == usart)
    {
        RCM_EnableAPB1PeriphReset(RCM_APB1_PERIPH_UART7);
        RCM_DisableAPB1PeriphReset(RCM_APB1_PERIPH_UART7);
    }
    else if (UART8 == usart)
    {
        RCM_EnableAPB1PeriphReset((uint32_t)RCM_APB1_PERIPH_UART8);
        RCM_DisableAPB1PeriphReset((uint32_t)RCM_APB1_PERIPH_UART8);
    }
}

/*!
 * @brief     Config the USART peripheral according to the specified parameters in the usartConfig
 *
 * @param     usart:         Select the USART or the UART peripheral
 *
 * @param     usartConfig:  pointer to a USART_Config_T structure
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_Config(USART_T* usart, USART_Config_T* usartConfig)
{
    uint32_t temp, fCLK, intDiv, fractionalDiv;

    usart->CTRL1_B.RXEN = usartConfig->mode & 0x01;
    usart->CTRL1_B.TXEN = usartConfig->mode >> 1;
    usart->CTRL1_B.PCFG = usartConfig->parity >> 1;
    usart->CTRL1_B.PCEN = usartConfig->parity & 0x01;
    usart->CTRL1_B.DBLCFG = usartConfig->wordLength;

    usart->CTRL2_B.STOPCFG = usartConfig->stopBits;

    usart->CTRL3_B.RTSEN = usartConfig->hardwareFlow & 0x01;
    usart->CTRL3_B.CTSEN = usartConfig->hardwareFlow >> 1;

    if ((usart == USART1) || (usart == USART6))
    {
        RCM_ReadPCLKFreq(NULL, &fCLK);
    }
    else
    {
        RCM_ReadPCLKFreq(&fCLK, NULL);
    }

    /* Compute the integer part */
    if (usart->CTRL1_B.OSMCFG != RESET) /*!< Oversampling by 8 */
    {
        intDiv = ((25 * fCLK) / (2 * (usartConfig->baudRate)));
    }
    else /*!< Oversampling by 16 */
    {
        intDiv = ((25 * fCLK) / (4 * (usartConfig->baudRate)));
    }

    temp = (intDiv / 100) << 4;
    fractionalDiv = intDiv - (100 * (temp >> 4));

    /* Implement the fractional part in the register */
    if (usart->CTRL1_B.OSMCFG != RESET) /*!< Oversampling by 8 */
    {
        temp |= ((((fractionalDiv * 8) + 50) / 100)) & ((uint8_t)0x07);
    }
    else /*!< Oversampling by 16 */
    {
        temp |= ((((fractionalDiv * 16) + 50) / 100)) & ((uint8_t)0x0F);
    }

    usart->BR = temp;
}

/*!
 * @brief     Fills each USART_InitStruct member with its default value
 *
 * @param     usartConfig:   pointer to a USART_Config_T structure which will be initialized
 *
 * @retval    None
 */
void USART_ConfigStructInit(USART_Config_T* usartConfig)
{
    usartConfig->baudRate = 9600;
    usartConfig->wordLength = USART_WORD_LEN_8B;
    usartConfig->stopBits = USART_STOP_BIT_1;
    usartConfig->parity = USART_PARITY_NONE ;
    usartConfig->mode = USART_MODE_TX_RX;
    usartConfig->hardwareFlow = USART_HARDWARE_FLOW_NONE;
}

/*!
 * @brief     Configuration communication clock
 *
 * @param     usart:  Select the USART or the UART peripheral
 *
 * @param     clockConfig:   Pointer to a USART_clockConfig_T structure
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3 and USART6
 */
void USART_ConfigClock(USART_T* usart, USART_ClockConfig_T* clockConfig)
{
    usart->CTRL2_B.CLKEN   = clockConfig->clock;
    usart->CTRL2_B.CPHA    = clockConfig->phase;
    usart->CTRL2_B.CPOL    = clockConfig->polarity;
    usart->CTRL2_B.LBCPOEN = clockConfig->lastBit;
}

/*!
 * @brief     Fills each clockConfig member with its default value
 *
 * @param     clockConfig:   Pointer to a USART_clockConfig_T structure
 *
 * @retval    None
 *
 * @note
 */
void USART_ConfigClockStructInit(USART_ClockConfig_T* clockConfig)
{
    clockConfig->clock     = USART_CLKEN_DISABLE;
    clockConfig->phase     = USART_CLKPHA_1EDGE;
    clockConfig->polarity  = USART_CLKPOL_LOW;
    clockConfig->lastBit   = USART_LBCP_DISABLE;
}

/*!
 * @brief     Enables the specified USART peripheral
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_Enable(USART_T* usart)
{
    usart->CTRL1_B.UEN = BIT_SET;
}

/*!
 * @brief     Disable the specified USART peripheral
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_Disable(USART_T* usart)
{
    usart->CTRL1_B.UEN = BIT_RESET;
}

/*!
 * @brief     Sets the system clock divider number
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @param     div:   specifies the divider number
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_ConfigPrescaler(USART_T* usart, uint8_t div)
{
    usart->GTPSC_B.PSC = div;
}

/*!
 * @brief     Enables the USART's 8x oversampling mode
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_EnableOverSampling8(USART_T* usart)
{
    usart->CTRL1_B.OSMCFG = BIT_SET;
}

/*!
 * @brief     Disable the USART's 8x oversampling mode
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_DisableOverSampling8(USART_T* usart)
{
    usart->CTRL1_B.OSMCFG = BIT_RESET;
}

/*!
 * @brief     Enables the USART's sample method
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_EnableOverSampling(USART_T* usart)
{
    usart->CTRL3_B.SAMCFG = BIT_SET;
}

/*!
 * @brief     Disable the USART's sample method
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_DisableOverSampling(USART_T* usart)
{
    usart->CTRL3_B.SAMCFG = BIT_RESET;
}

/*!
 * @brief     Transmits single data
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @param     data:  the data to transmit
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_TxData(USART_T* usart, uint16_t data)
{
    usart->DATA_B.DATA = data;
}

/*!
 * @brief     Returns the most recent received data
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
uint16_t USART_RxData(USART_T* usart)
{
    return (uint16_t)(usart->DATA_B.DATA);
}

/*!
 * @brief     Configures the address of the USART node
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @param     address: Indicates the address of the USART node
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_Address(USART_T* usart, uint8_t address)
{
    usart->CTRL2_B.ADDR = address;
}

/*!
 * @brief     Enable USART Receiver in mute mode
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_EnableMuteMode(USART_T* usart)
{
    usart->CTRL1_B.RXMUTEEN = BIT_SET;
}

/*!
 * @brief     Disable USART Receiver in active mode
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_DisableMuteMode(USART_T* usart)
{
    usart->CTRL1_B.RXMUTEEN = BIT_RESET;
}

/*!
 * @brief     Selects the USART WakeUp method.
 *
 * @param     usart:  Select the USART or the UART peripheral
 *
 * @param     wakeup: Specifies the selected USART auto baud rate method
 *                    This parameter can be one of the following values:
 *                    @arg USART_WAKEUP_IDLE_LINE    : WakeUp by an idle line detection
 *                    @arg USART_WAKEUP_ADDRESS_MARK : WakeUp by an address mark
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_ConfigWakeUp(USART_T* usart, USART_WAKEUP_T wakeup)
{
    usart->CTRL1_B.WUPMCFG = wakeup;
}

/*!
 * @brief     Sets the USART LIN Break detection length
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @param     length:  Specifies the LIN break detection length
 *                     This parameter can be one of the following values:
 *                     @arg USART_LBDL_10B : 10-bit break detection
 *                     @arg USART_LBDL_11B : 11-bit break detection
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_ConfigLINBreakDetectLength(USART_T* usart, USART_LBDL_T length)
{
    usart->CTRL2_B.LBDLCFG = length;
}

/*!
 * @brief     Enables the USART LIN MODE
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_EnableLIN(USART_T* usart)
{
    usart->CTRL2_B.LINMEN = BIT_SET;
}

/*!
 * @brief     Disable the USART LIN MODE
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_DisableLIN(USART_T* usart)
{
    usart->CTRL2_B.LINMEN = BIT_RESET;
}

/*!
 * @brief     Transmits break characters
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_TxBreak(USART_T* usart)
{
    usart->CTRL1_B.TXBF = BIT_SET;
}

/*!
 * @brief     Enables USART Half Duplex communication
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_EnableHalfDuplex(USART_T* usart)
{
    usart->CTRL3_B.HDEN = BIT_SET;
}

/*!
 * @brief     Disable USART Half Duplex communication
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_DisableHalfDuplex(USART_T* usart)
{
    usart->CTRL3_B.HDEN = BIT_RESET;
}

/*!
 * @brief     Sets the specified USART guard time
 *
 * @param     usart:     Select the USART or the UART peripheral
 *
 * @param     guardTime: Specifies the guard time
 *
 * @retval    None
 *
 * @note      The specified USART guard time is not available for UART4 and UART5
 */
void USART_ConfigGuardTime(USART_T* usart, uint8_t guardTime)
{
    usart->GTPSC_B.GRDT = guardTime;
}

/*!
 * @brief     Enables the USART Smart Card mode
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The Smart Card mode is not available for UART4 and UART5
 */
void USART_EnableSmartCard(USART_T* usart)
{
    usart->CTRL3_B.SCEN = BIT_SET;
}

/*!
 * @brief     Disable the USART Smart Card mode
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The Smart Card mode is not available for UART4 and UART5
 */
void USART_DisableSmartCard(USART_T* usart)
{
    usart->CTRL3_B.SCEN = BIT_RESET;
}

/*!
 * @brief     Enables NACK transmission
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The Smart Card mode is not available for UART4 and UART5
 */
void USART_EnableSmartCardNACK(USART_T* usart)
{
    usart->CTRL3_B.SCNACKEN = BIT_SET;
}

/*!
 * @brief     Disable NACK transmission
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The Smart Card mode is not available for UART4 and UART5
 */
void USART_DisableSmartCardNACK(USART_T* usart)
{
    usart->CTRL3_B.SCNACKEN = BIT_RESET;
}

/*!
 * @brief     Configures the USART's IrDA interface
 *
 * @param     usart:    Select the USART or the UART peripheral
 *
 * @param     IrDAMode: Specifies the IrDA mode
 *                      This parameter can be one of the following values:
 *                      @arg USART_IRDALP_NORMAL    : Normal
 *                      @arg USART_IRDALP_LOWPOWER  : Low-Power
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_ConfigIrDA(USART_T* usart, USART_IRDALP_T IrDAMode)
{
    usart->CTRL3_B.IRLPEN = IrDAMode;
}

/*!
 * @brief     Enables the USART's IrDA interface
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_EnableIrDA(USART_T* usart)
{
    usart->CTRL3_B.IREN = BIT_SET;
}

/*!
 * @brief     Disable the USART's IrDA interface
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_DisableIrDA(USART_T* usart)
{
    usart->CTRL3_B.IREN = BIT_RESET;
}

/*!
 * @brief     Enables the USART DMA interface
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @param     dmaReq:  Specifies the DMA request
 *                     This parameter can be one of the following values:
 *                     @arg USART_DMA_TX    : USART DMA receive request
 *                     @arg USART_DMA_RX    : USART DMA transmit request
 *                     @arg USART_DMA_TX_RX : USART DMA transmit/receive request
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_EnableDMA(USART_T* usart, USART_DMA_T dmaReq)
{
    usart->CTRL3_B.DMARXEN = dmaReq & 0x01;
    usart->CTRL3_B.DMATXEN = dmaReq >> 1;
}

/*!
 * @brief     Disable the USART DMA interface
 *
 * @param     usart:   Select the USART or the UART peripheral
 *
 * @param     dmaReq:  Specifies the DMA request
 *                     This parameter can be one of the following values:
 *                     @arg USART_DMA_TX    : USART DMA receive request
 *                     @arg USART_DMA_RX    : USART DMA transmit request
 *                     @arg USART_DMA_TX_RX : USART DMA transmit/receive request
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_DisableDMA(USART_T* usart, USART_DMA_T dmaReq)
{
    usart->CTRL3_B.DMARXEN = !(dmaReq & 0x01);
    usart->CTRL3_B.DMATXEN = !(dmaReq >> 1);
}

/*!
 * @brief     Enable the specified USART interrupts
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @param     interrupt: Specifies the USART interrupts sources
 *                       The parameter can be one of following values:
 *                       @arg USART_INT_PE      : Parity error interrupt
 *                       @arg USART_INT_TXBE    : Tansmit data buffer empty interrupt
 *                       @arg USART_INT_TXC     : Transmission complete interrupt
 *                       @arg USART_INT_RXBNE   : Receive data buffer not empty interrupt
 *                       @arg USART_INT_IDLE    : Idle line detection interrupt
 *                       @arg USART_INT_LBD     : LIN break detection interrupt
 *                       @arg USART_INT_CTS     : CTS change interrupt
 *                       @arg USART_INT_ERR     : Error interrupt(Frame error, noise error, overrun error)
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_EnableInterrupt(USART_T* usart, USART_INT_T interrupt)
{
    uint32_t temp;

    temp = (uint32_t)(interrupt & 0xffff);

    if (interrupt & 0x10000)
    {
        usart->CTRL1 |= temp;
    }

    if (interrupt & 0x20000)
    {
        usart->CTRL2 |= temp;
    }

    if (interrupt & 0x40000)
    {
        usart->CTRL3 |= temp;
    }
}

/*!
 * @brief     Disables the specified USART interrupts
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @param     interrupt: Specifies the USART interrupts sources
 *                       The parameter can be one of following values:
 *                       @arg USART_INT_PE      : Parity error interrupt
 *                       @arg USART_INT_TXBE    : Tansmit data buffer empty interrupt
 *                       @arg USART_INT_TXC     : Transmission complete interrupt
 *                       @arg USART_INT_RXBNE   : Receive data buffer not empty interrupt
 *                       @arg USART_INT_IDLE    : Idle line detection interrupt
 *                       @arg USART_INT_LBD     : LIN break detection interrupt
 *                       @arg USART_INT_CTS     : CTS change interrupt
 *                       @arg USART_INT_ERR     : Error interrupt(Frame error, noise error, overrun error)
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_DisableInterrupt(USART_T* usart, USART_INT_T interrupt)
{
    uint32_t temp;

    temp = (uint32_t)~(interrupt & 0xffff);

    if (interrupt & 0x10000)
    {
        usart->CTRL1 &= temp;
    }

    if (interrupt & 0x20000)
    {
        usart->CTRL2 &= temp;
    }

    if (interrupt & 0x40000)
    {
        usart->CTRL3 &= temp;
    }
}

/*!
 * @brief     Read the specified USART flag
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @param     flag: Specifies the flag to check
 *                  The parameter can be one of following values:
 *                  @arg USART_FLAG_CTS     : CTS Change flag (not available for UART4 and UART5)
 *                  @arg USART_FLAG_LBD     : LIN Break detection flag
 *                  @arg USART_FLAG_TXBE    : Transmit data buffer empty flag
 *                  @arg USART_FLAG_TXC     : Transmission Complete flag
 *                  @arg USART_FLAG_RXBNE   : Receive data buffer not empty flag
 *                  @arg USART_FLAG_IDLE    : Idle Line detection flag
 *                  @arg USART_FLAG_OVRE    : OverRun Error flag
 *                  @arg USART_FLAG_NE      : Noise Error flag
 *                  @arg USART_FLAG_FE      : Framing Error flag
 *                  @arg USART_FLAG_PE      : Parity Error flag
 *
 * @retval    The new state of flag (SET or RESET)
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
uint8_t USART_ReadStatusFlag(USART_T* usart, USART_FLAG_T flag)
{
    return (usart->STS & flag) ? SET : RESET;
}

/*!
 * @brief     Clears the USARTx's pending flags
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @param     flag: Specifies the flag to clear
 *                  The parameter can be one of following values:
 *                  @arg USART_FLAG_CTS     : CTS Change flag (not available for UART4 and UART5)
 *                  @arg USART_FLAG_LBD     : LIN Break detection flag
 *                  @arg USART_FLAG_TXC     : Transmission Complete flag
 *                  @arg USART_FLAG_RXBNE   : Receive data buffer not empty flag
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_ClearStatusFlag(USART_T* usart, USART_FLAG_T flag)
{
    usart->STS &= (uint32_t)~flag;
}

/*!
 * @brief     Read the specified USART interrupt flag
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @param     flag:  Specifies the USART interrupt source to check
 *                        The parameter can be one of following values:
 *                        @arg USART_INT_TXBE    : Tansmit data buffer empty interrupt
 *                        @arg USART_INT_TXC     : Transmission complete interrupt
 *                        @arg USART_INT_RXBNE   : Receive data buffer not empty interrupt
 *                        @arg USART_INT_IDLE    : Idle line detection interrupt
 *                        @arg USART_INT_LBD     : LIN break detection interrupt
 *                        @arg USART_INT_CTS     : CTS change interrupt
 *                        @arg USART_INT_OVRE_RX : OverRun Error interruptpt if the RXBNFLG bit is set
 *                        @arg USART_INT_OVRE_ER : OverRun Error interruptpt if the EIE bit is set
 *                        @arg USART_INT_NE      : Noise Error interrupt
 *                        @arg USART_INT_FE      : Framing Error interrupt
 *                        @arg USART_INT_PE      : Parity error interrupt
 *
 * @retval    The new state of flag (SET or RESET)
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
uint8_t USART_ReadIntFlag(USART_T* usart, USART_INT_T flag)
{
    uint32_t itFlag, srFlag;

    if (flag & 0x10000)
    {
        itFlag = usart->CTRL1 & flag & 0xffff;
    }
    else if (flag & 0x20000)
    {
        itFlag = usart->CTRL2 & flag & 0xffff;
    }
    else
    {
        itFlag = usart->CTRL3 & flag & 0xffff;
    }

    srFlag = flag >> 24;
    srFlag = (uint32_t)(1 << srFlag);
    srFlag = usart->STS & srFlag;

    if (srFlag && itFlag)
    {
        return SET;
    }

    return RESET;
}

/*!
 * @brief     Clears the USART interrupt pending bits
 *
 * @param     usart: Select the USART or the UART peripheral
 *
 * @param     flag: Specifies the interrupt pending bit to clear
 *                  The parameter can be one of following values:
 *                  @arg USART_INT_RXBNE : Receive data buffer not empty interrupt
 *                  @arg USART_INT_TXC   : Transmission complete interrupt
 *                  @arg USART_INT_LBD   : LIN break detection interrupt
 *                  @arg USART_INT_CTS   : CTS change interrupt
 *
 * @retval    None
 *
 * @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8
 */
void USART_ClearIntFlag(USART_T* usart, USART_INT_T flag)
{
    uint32_t srFlag;

    srFlag = flag >> 24;
    srFlag = (uint32_t)(1 << srFlag);

    usart->STS &= (uint32_t)~srFlag;
}

/**@} end of group USART_Functions */
/**@} end of group USART_Driver */
/**@} end of group APM32F4xx_StdPeriphDriver */
